{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "# this is partly adapted from Lilian Weng's implementation\n",
    "# https://github.com/lilianweng/multi-armed-bandit\n",
    "import random\n",
    "\n",
    "class Bandit:\n",
    "    def __init__(self, K=2, probs=None):\n",
    "        \"\"\"A multi-armed bandit\n",
    "        \n",
    "        Parameters:\n",
    "        -----------\n",
    "        K - the number of arms\n",
    "        \"\"\"\n",
    "        self.K = K\n",
    "        if probs is None:\n",
    "            self.probs = [\n",
    "                random.random() for _ in range(self.K)\n",
    "            ]\n",
    "        else:\n",
    "            assert len(probs) == K\n",
    "            self.probs = probs\n",
    "\n",
    "        self.best_probs = max(self.probs)\n",
    "\n",
    "    def play(self, i):\n",
    "        \"\"\"Playing the i-th machine.\n",
    "        \n",
    "        Returns a reward as 1 or 0.\n",
    "        \"\"\"\n",
    "        if random.random() < self.probs[i]:\n",
    "            return 1\n",
    "        else:\n",
    "            return 0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 316,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Agent:\n",
    "    def __init__(self, env):\n",
    "        \"\"\"\n",
    "        An abstract agent\n",
    "        \n",
    "        Parameters:\n",
    "        -----------\n",
    "        env - an environment (a bandit)\n",
    "        \"\"\"\n",
    "        \n",
    "        self.env = env\n",
    "        self.listeners = {}\n",
    "        self.metrics = {}\n",
    "        self.reset()\n",
    "        \n",
    "    def reset(self):\n",
    "        for k in self.metrics:\n",
    "            self.metrics[k] = []\n",
    "\n",
    "    def add_listener(self, name, fun):\n",
    "        \"\"\"Add a listener to record a metric\n",
    "        \"\"\"\n",
    "        self.listeners[name] = fun\n",
    "        self.metrics[name] = []\n",
    "        \n",
    "    def run_metrics(self, i):\n",
    "        \"\"\"Calculate metrics after an action i\"\"\"\n",
    "        for key, fun in self.listeners.items():\n",
    "            fun(self, i, key)\n",
    "\n",
    "    def run_one_step(self):\n",
    "        \"\"\"A single choice.\"\"\"            \n",
    "        raise NotImplementedError\n",
    "        \n",
    "    def run(self, n_steps):\n",
    "        \"\"\"plays n_steps of choices        \n",
    "        \"\"\"\n",
    "        raise NotImplementedError"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 317,
   "metadata": {},
   "outputs": [],
   "source": [
    "class UCB1(Agent):\n",
    "    def __init__(self, env, alpha=2.):\n",
    "        \"\"\"\n",
    "        The UCB1 agent\n",
    "        \n",
    "        Parameters:\n",
    "        -----------\n",
    "        env - an environment (a bandit)\n",
    "        alpha - the alpha parameter\n",
    "        \"\"\"\n",
    "        self.alpha = alpha\n",
    "        super(UCB1, self).__init__(env)\n",
    "    \n",
    "    def run_exploration(self):\n",
    "        \"\"\"Initial exploration\n",
    "        \"\"\"\n",
    "        for i in range(self.env.K):\n",
    "            self.estimates[i] = self.env.play(i)\n",
    "            self.counts[i] += 1\n",
    "            self.history.append(i)\n",
    "            self.run_metrics(i)            \n",
    "            self.t += 1\n",
    "    \n",
    "    def update_estimate(self, i, r):\n",
    "        \"\"\"Incremental update of estimate for arm i\n",
    "        \"\"\"\n",
    "        self.estimates[i] += (r - self.estimates[i]) / (self.counts[i] + 1)\n",
    "\n",
    "    def reset(self):\n",
    "        self.history = []\n",
    "        self.t = 0\n",
    "        self.counts = [0] * self.env.K\n",
    "        self.estimates = [None] * self.env.K\n",
    "        super(UCB1, self).reset()\n",
    "    \n",
    "    def run(self, n_steps):\n",
    "        \"\"\"plays n_steps of choices\n",
    "        \n",
    "        This count does not include the exploration phase.\n",
    "        \"\"\"\n",
    "        assert self.env is not None\n",
    "        self.reset()\n",
    "        if self.estimates[0] is None:\n",
    "            self.run_exploration()\n",
    "        for _ in range(n_steps):\n",
    "            i = self.run_one_step()\n",
    "            self.counts[i] += 1\n",
    "            self.history.append(i)\n",
    "            self.run_metrics(i)\n",
    "\n",
    "    def upper_bound(self, i):\n",
    "        return np.sqrt(\n",
    "            self.alpha * np.log(self.t) / (1 + self.counts[i])\n",
    "        )\n",
    "   \n",
    "    def run_one_step(self):\n",
    "        \"\"\"A single choice.\n",
    "        \n",
    "        Pick the best (optimistic) choice\n",
    "        (with consideration of upper confidence bounds)\n",
    "        \"\"\"\n",
    "        i = max(\n",
    "            range(self.env.K),\n",
    "            key=lambda i: self.estimates[i] + self.upper_bound(i)\n",
    "        )\n",
    "        r = self.env.play(i)\n",
    "        self.update_estimate(i, r)\n",
    "        self.t += 1\n",
    "        return i"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 318,
   "metadata": {},
   "outputs": [],
   "source": [
    "from scipy import stats\n",
    "\n",
    "def update_regret(agent, i, key):\n",
    "    \"\"\"update regret given an agent and a new action\n",
    "    \"\"\"\n",
    "    regret = agent.env.best_probs - agent.env.probs[i]\n",
    "    if agent.metrics[key]:\n",
    "        agent.metrics[key].append(\n",
    "            agent.metrics[key][-1] + regret\n",
    "        )\n",
    "    else:\n",
    "        agent.metrics[key] = [regret]\n",
    "        \n",
    "def update_rank_corr(agent, i, key):\n",
    "    \"\"\"rank correlation to observe convergence\"\"\"\n",
    "    if agent.t < agent.env.K:\n",
    "        agent.metrics[key].append(0.0)\n",
    "    else:\n",
    "        agent.metrics[key].append(\n",
    "            stats.spearmanr(agent.env.probs, agent.estimates)[0]\n",
    "        )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 319,
   "metadata": {},
   "outputs": [],
   "source": [
    "%matplotlib inline\n",
    "import pandas as pd\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "\n",
    "def plot_stats(title):\n",
    "    df = pd.DataFrame(agent.metrics)\n",
    "    df['t'] = list(range(len(df)))\n",
    "    ax = df.plot(x='t', y='regret', legend=False)\n",
    "    ax2 = ax.twinx()\n",
    "    ax.spines['left'].set_color('b')\n",
    "    ax.spines['left'].set_linewidth(1.5)\n",
    "    ax.tick_params(axis='y', colors='b')\n",
    "\n",
    "    df.plot(x='t', y='corr', ax=ax2, legend=False, color=\"r\")\n",
    "    ax.spines['right'].set_color('r')\n",
    "    ax.spines['right'].set_linewidth(1.5)\n",
    "    ax2.tick_params(axis='y', colors='r')\n",
    "\n",
    "    ax.figure.legend(loc='center', bbox_to_anchor=(0.7, 0.5))\n",
    "    plt.title(title)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 327,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 2 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "random.seed(42.0)  # int(time.time())\n",
    "bandit = Bandit(20)\n",
    "agent = UCB1(bandit, alpha=2.0)\n",
    "agent.add_listener('regret', update_regret)\n",
    "agent.add_listener('corr', update_rank_corr)\n",
    "agent.run(5000)\n",
    "plot_stats('alpha=2.0')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 328,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 2 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "random.seed(42.0)  # int(time.time())\n",
    "bandit = Bandit(20)\n",
    "agent = UCB1(bandit, alpha=0.5)\n",
    "agent.add_listener('regret', update_regret)\n",
    "agent.add_listener('corr', update_rank_corr)\n",
    "agent.run(5000)\n",
    "plot_stats('alpha=0.5')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
